package ru.amse.tsyganov.jumleditor.graphicaleditor;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Point;

import ru.amse.tsyganov.jumleditor.commands.Command;
import ru.amse.tsyganov.jumleditor.commands.CommandFactory;
import ru.amse.tsyganov.jumleditor.properties.StringProperty;
import ru.amse.tsyganov.jumleditor.view.common.EdgeView;
import ru.amse.tsyganov.jumleditor.view.common.StateView;
import ru.amse.tsyganov.jumleditor.view.common.ViewElement;
import ru.amse.tsyganov.jumleditor.view.preferences.Cursors;

/*package*/ class TextInputMode extends EditorMode {
	
	private final GraphicalEditor graphicalEditor;
	
	private ViewElement selectedViewElement;
	
	private StringProperty stringProperty;
	
	private KeyListener keyListener;
	
	public TextInputMode(GraphicalEditor graphicalEditor) {
		if (graphicalEditor == null) {
			throw new IllegalArgumentException();
		}
		this.graphicalEditor = graphicalEditor;
		
	}

	@Override
	public void initState() {
		graphicalEditor.getCanvas().setCursor(Cursors.getCursorArrow());
		graphicalEditor.getActivityGraphView().setPaintConnectionPoints(false);
		graphicalEditor.getCanvas().redraw();
		
		selectedViewElement = null;
		
		if (graphicalEditor.getActivityGraphView().getSelectedItems().
				selectedStatesSize() == 1) {
			
			selectedViewElement = graphicalEditor.getActivityGraphView().
				getSelectedItems().getSelectedStates().iterator().next();
		}
		
		if (graphicalEditor.getActivityGraphView().getSelectedItems().
				selectedTransitionsSize() == 1) {
			
			selectedViewElement = graphicalEditor.getActivityGraphView().
				getSelectedItems().getSelectedTransitions().iterator().next();
		}
		
		if (selectedViewElement == null) {
			throw new IllegalStateException();
		}
			
		if (selectedViewElement.getMainProperty() != null) {
			stringProperty = selectedViewElement.getMainProperty();

			graphicalEditor.getTextInputField().setEnabled(true);

			graphicalEditor.getTextInputField().setText(
					stringProperty.getStringPropertyValue());

			placeTextField(graphicalEditor.getCoordinates());

			graphicalEditor.getTextInputField().setVisible(true);
			graphicalEditor.getTextInputField().setFocus();

			keyListener = new KeyListener() {

				public void keyPressed(KeyEvent e) {
					if (e.keyCode == SWT.KEYPAD_CR || e.keyCode == SWT.CR) {

						leaveState();
					}
				}

				public void keyReleased(KeyEvent e) {
				}

			};
			graphicalEditor.getTextInputField().addKeyListener(keyListener);
		}
	}

	private void placeTextField(Coordinates coord) {
		if (selectedViewElement instanceof StateView) { 
			StateView selectedStateView = 
				(StateView) selectedViewElement;
			
			final int DETAULT_TEXT_SIZE = 70;
			final int TOP_BOTTOM_SIZE = 10;
			final int LEFT_RIGHT_MARGIN = 4;
							
			graphicalEditor.getTextInputField().setBounds(
					coord.fromModelXToScreenX(
							selectedStateView.getX() + LEFT_RIGHT_MARGIN),
					coord.fromModelYToScreenY(
							selectedStateView.getTextOutputPoint().y - TOP_BOTTOM_SIZE),
					Math.max(selectedStateView.getWidth() - 2 * LEFT_RIGHT_MARGIN, 
							DETAULT_TEXT_SIZE),
					2 * TOP_BOTTOM_SIZE);
		}
		
		if (selectedViewElement instanceof EdgeView) { 
			EdgeView selectedTransitionView = 
				(EdgeView) selectedViewElement;
			
			Point extent = selectedTransitionView.getStringExtent();
			Point centerPoint = selectedTransitionView.getTextOutputPoint();
			
			assert extent != null;
			
			final int DETAULT_TEXT_SIZE = 70;
			final int TOP_BOTTOM_MARGIN = 3;
			final int LEFT_RIGHT_MARGIN = 6;
			
			graphicalEditor.getTextInputField().setBounds(
					coord.fromModelXToScreenX(
							centerPoint.x - extent.x / 2 - LEFT_RIGHT_MARGIN),
					coord.fromModelYToScreenY(
							centerPoint.y - extent.y / 2 - TOP_BOTTOM_MARGIN),
					Math.max(extent.x + 2 * LEFT_RIGHT_MARGIN, DETAULT_TEXT_SIZE),
					extent.y + 2 * TOP_BOTTOM_MARGIN);
		}
	}
	
	@Override
	public void keyPressed(KeyEvent e) {
	}

	@Override
	public void keyReleased(KeyEvent e) {
	}

	@Override
	public void mouseDoubleClick(MouseEvent e) {
		leaveStateIfNeed(e);
	}

	@Override
	public void mouseDown(MouseEvent e) {
		leaveStateIfNeed(e);
	}

	@Override
	public void mouseMove(MouseEvent e) {
	}

	@Override
	public void mouseUp(MouseEvent e) {
		leaveStateIfNeed(e);
	}

	@Override
	public void paintControl(PaintEvent e, Coordinates coordinates) {
		placeTextField(coordinates);
	}

	private void leaveState() {
		String newText = graphicalEditor.getTextInputField().getText(); 
		
		if (!newText.equals(stringProperty.getPropertyValue())) {
			Command c = CommandFactory.
				createChangePropertyCommand(stringProperty, newText);
			
			if (selectedViewElement instanceof StateView) {
				StateView stateView = (StateView) selectedViewElement;
				int oldWidth = stateView.getWidth();
				c.execute();
				graphicalEditor.getCanvas().update();
				int newWidth = stateView.getWidth();
				c.unexecute();
				stateView.setWidth(oldWidth);
				if (oldWidth != newWidth) {
					List<Command> commands = new ArrayList<Command>(2);
					commands.add(c);
					commands.add(CommandFactory.createResizeStateCommand(stateView,
							stateView.getX(), stateView.getY(), 
							newWidth, stateView.getHeight()));
					Command composite = CommandFactory.createCompositeCommand(commands);
					graphicalEditor.getViewsManager().executeCommand(composite);
				} else {
					graphicalEditor.getViewsManager().executeCommand(c);
				}
			} else {
				graphicalEditor.getViewsManager().executeCommand(c);
			}
		}
		graphicalEditor.getTextInputField().setVisible(false);
		graphicalEditor.getTextInputField().setEnabled(false);
		graphicalEditor.getTextInputField().removeKeyListener(keyListener);
		graphicalEditor.getCanvas().redraw();
		graphicalEditor.setFocus();
		graphicalEditor.setEditorMode(graphicalEditor.getSelectionMode());
	}
	
	private void leaveStateIfNeed(MouseEvent e) {
		StateView selectedView = 
			graphicalEditor.getActivityGraphView().getStateView(e.x, e.y);
		
		EdgeView edgeView = 
			graphicalEditor.getActivityGraphView().getTransitionView(e.x, e.y);
		
		if (selectedView != selectedViewElement && 
				edgeView != selectedViewElement) {
			
			leaveState();
		}
	}
	
}
